#pragma once
#include <iostream>
#include <string>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

static const std::string defaultip = "0.0.0.0";
static const uint16_t defaultport = 8080;
static const int default_backlog = 10;
static const int BUFSIZE = 1024;

class UdpServer
{
private:
    std::string _server_ip;
    uint16_t _server_port;
    int _listen_sockfd;

public:
    UdpServer(const std::string &ip = defaultip, const uint16_t &port = defaultport)
        : _server_ip(ip), _server_port(port), _listen_sockfd(-1) {}

    // 初始化服务器
    void Init()
    {
        // 创建通信套接字文件
        _listen_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_listen_sockfd < 0)
        {
            std::cerr << "create socket fail" << std::endl;
            std::abort();
        }
        // 绑定ip和端口号
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(_server_port);
        // server.sin_addr.s_addr = inet_addr(_server_ip.c_str());
        inet_aton(_server_ip.c_str(), &(server.sin_addr));

        socklen_t len = sizeof(server);
        int bind_ret = bind(_listen_sockfd, (struct sockaddr *)&server, len);
        if (bind_ret < 0)
        {
            std::cerr << "bind ip and port fail" << std::endl;
            std::abort();
        }

        // 设置端口地址重用
        int val = 1;
        setsockopt(_listen_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &val, sizeof(val));

        // 开始监听
        int listen_ret = listen(_listen_sockfd, default_backlog);
        if (listen_ret < 0)
        {
            std::cerr << "server listen fail " << std::endl;
            std::abort();
        }
    }

    // 运行服务器
    void Run()
    {
        while (1)
        {
            // 获取连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);

            int sockfd = accept(_listen_sockfd, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                std::cerr << "server accept fail" << std::endl;
                continue;
            }

            // 获取客户端ip和端口号
            const std::string clientip = inet_ntoa(client.sin_addr);
            const uint64_t clientport = ntohs(client.sin_port);

            // 接收和发送信息
            while (true)
            {
                // read是面向字节流的，Tcp也是，所以可以用read像读文件一样读取网络的内容
                char buffer[4096];
                ssize_t ret = read(sockfd, buffer, sizeof(buffer));
                if (ret > 0)
                {
                    buffer[ret] = 0;
                    std::cout << "client say#" << buffer << std::endl;
                    std::string echo_string = "tcpserver echo#";
                    echo_string += buffer;

                    int n = write(sockfd, echo_string.c_str(), echo_string.size());
                    if (n < 0)
                        std::cout << "write error" << std::endl;
                }
                else if (ret == 0)
                {
                    std::cout << "server close sockfd:" << sockfd << std::endl;
                    break;
                }
                else
                {
                    std::cout << "server read error" << std::endl;
                    break;
                }
            }
            close(sockfd);
        }
    }
};